Консольные приложения
=====================

Консольные приложения главным образом используются для выполнения вторичных или фоновых задач,
таких как генерация кода, компиляция поискового индекса, отправка сообщений электронной почты и т.д.
Yii предоставляет инструмент для разработки консольных приложений, придерживаясь
объектно-ориентированного подхода. Он позволяет консольному приложению получить доступ
к ресурсам, которые использует основное веб-приложение (например, к базе данных).


Обзор
-----
Каждая консольная задача представлена в Yii как [команда|CConsoleCommand].
Консольная команда описывается в классе, наследуемом от [CConsoleCommand].

После использования `yiic webapp` для создания начального прототипа приложения,
в `protected` будут два файла:

* `yiic` — скрипт для Linux/Unix;
* `yiic.bat` — скрипт для Windows.

В консоли можно ввести следующие команды:

~~~
cd protected
yiic help
~~~

После ввода будет отображён список всех доступных на данный момент команд.
По умолчанию это команды, предоставляемые Yii (так называемые **системные команды**)
и команды, разработанные для конкретных приложений (так называемые **пользовательские команды**).

Для получения справки по команде можно запустить

~~~
yiic help <имя-команды>
~~~

Для запуска команды используется следующий формат:

~~~
yiic <имя-команды> [параметры…]
~~~


Создание команд
---------------

Консольные команды находятся в файлах с классами в папке, указанной в
[CConsoleApplication::commandPath]. По умолчанию это `protected/commands`.

Класс консольной команды должен быть унаследован от [CConsoleCommand]. Имя класса
должно быть вида `XyzCommand`, где `Xyz` соответствует имени команды, первая буква
которого приведена к верхнему регистру. К примеру, команда `sitemap` должна использовать
класс `SitemapCommand`. Имена консольных команд регистрозависимы.

> Tip|Подсказка: Конфигурируя [CConsoleApplication::commandMap], можно при желании изменить порядок
именования и расположения классов команд.

Для создания новой команды необходимо либо реализовать метод [CConsoleCommand::run()],
либо одно или несколько действий (будут описаны далее).

При вводе консольной команды приложение запускает метод [CConsoleCommand::run()].
Параметры метода передаются в соответствии с следующим заголовком:

~~~
[php]
public function run($args) { ... }
~~~

где `$args` — дополнительные параметры, переданные из командной строки.

Внутри консольной команды для получения доступа к экземпляру консольного приложения
можно использовать `Yii::app()`. Через полученный экземпляр можно обращаться
к различным компонентам, таким как соединение с базой данных (`Yii::app()->db`).
Насколько можно судить, это очень похоже на обычное веб-приложение.

> Info|Информация: Начиная с версии 1.1.1 можно создавать глобальные команды,
которые используются ***всеми*** приложениями. Для этого определяется
переменная окружения `YII_CONSOLE_COMMANDS` и в её значение записывается
путь к директории с классами глобальных консольных команд.


Действие консольной команды
---------------------------

> Note|Примечание: Данная возможность доступна начиная с версии 1.1.5.

Часто в консольной команде требуется работать с различными параметрами.
Часть из них могут быть обязательными, а часть нет. Также может потребоваться
реализовать субкоманды для выполнения различных подзадач. Всё это упрощается при
использовании действий.

Действие консольной команды — метод в её классе. Имя метода должно быть
вида `actionXyz`, где `Xyz` соответствует имени действия и первой буквой, приведённой
к верхнему регистру. К примеру, метод `actionIndex` задаёт действие
с именем `index`.

Для того, чтобы запустить определённое действие, используется следующий формат команды:

~~~
yiic <имя-команды> <имя-действия> --параметр1=значение1 --параметр2=значение2 ...
~~~

Дополнительные пары имя-значение передаются методу действия как именованные параметры.
Значение опции `xyz` соответствует параметру `$xyz` метода действия.
К примеру, если мы определим следующий класс команды:

~~~
[php]
class SitemapCommand extends CConsoleCommand
{
    public function actionIndex($type, $limit=5) { ... }
    public function actionInit() { ... }
}
~~~

То все следующие консольные команды вызовут `actionIndex('News', 5)`:

~~~
yiic sitemap index --type=News --limit=5

// $limit принимает значение по умолчанию
yiic sitemap index --type=News

// $limit принимает значение по умолчанию.
// Так как 'index' — действие по умолчанию, мы можем опустить имя действия.
yiic sitemap --type=News

// порядок опций не важен
yiic sitemap index --limit=5 --type=News
~~~

Если значение опции не указано (то есть `--type` вместо `--type=News`), соответствующему
параметру действия будет присвоено значение `true`.

> Note|Примечание: Альтернативные форматы указания опций, такие как
> `--type News` или `-t News` не поддерживаются.

Если объявить параметр как массив, он сможет принять массив значений:

~~~
[php]
public function actionIndex(array $types) { ... }
~~~

Чтобы передать массив значений необходимо указать одну и ту же опцию несколько раз:

~~~
yiic sitemap index --types=News --types=Article
~~~

Команда, приведённая выше, запустит `actionIndex(array('News', 'Article'))`.

Начиная с версии 1.1.6, Yii позволяет использовать анонимные параметры действий и
глобальные опции.

Анонимные параметры — это параметры командной строки, не являющиеся опциями.
К примеру, в команде `yiic sitemap index --limit=5 News` встречается
анонимный параметр со значением `News`. Именованный параметр (опция) `limit`
принимает значение, равное 5.

Для того, чтобы использовать анонимные параметры, действие должно описать параметр
с именем `$args`:

~~~
[php]
public function actionIndex($limit=10, $args=array()) {...}
~~~

В массиве `$args` будут содержаться все доступные значения анонимных параметров.

Глобальные опции — это параметры командной строки, общие для всех действий команды.
К примеру, нам может понадобиться для команды с несколькими действиями завести общую
опцию `verbose`. Конечно, можно определить параметр `$verbose` для каждого действия, но
лучше задать его **public свойством** класса команды, что автоматически сделает
`verbose` глобальной опцией:

~~~
[php]
class SitemapCommand extends CConsoleCommand
{
	public $verbose=false;
	public function actionIndex($type) {...}
}
~~~

Приведённый код позволяет использовать опцию `verbose`:

~~~
yiic sitemap index --verbose=1 --type=News
~~~


Код возврата
------------

> Note|Примечание: возможность указать код возврата в консольной команде
  появилась в версии 1.1.11.

При автоматическом запуске консольных команд, например, по cron или используя
сервер непрерывной интеграции, важно знать, завершилось ли выполнение команды с
ошибкой или успешно. Как раз для этого и предназначены коды возврата.

Данные коды являются целочисленными значениями от 0 до 254 (данный интервал
задан в [PHP](http://www.php.net/manual/ru/function.exit.php)),
где 0 возвращается в случае успеха, а все остальные значения используются для
различных ошибок.

Как в методе `run()`, так и в действиях команды вы можете вернуть целое число.
Оно будет использовано в качестве кода возврата.

Пример:

~~~
[php]
if (/* ошибка */) {
    return 1; // выходим с кодом 1
}
// … всякая всячина …
return 0; // всё хорошо, выходим с кодом 0
~~~

Если консольная команда ничего не возвращает, приложение завершается с кодом 0.

Настройка консольного приложения
--------------------------------

По умолчанию, если приложение создаётся с использованием `yiic webapp`, конфигурация
консольного приложения находится в `protected/config/console.php`. Как и конфигурация
веб-приложения, данный файл является PHP-скриптом, возвращающим массив с начальными
значениями экземпляра консольного приложения. То есть в данном файле можно задать
любое public свойство [CConsoleApplication].

Так как консольные команды часто создаются для поддержки веб-приложения, требуется
использовать те же ресурсы (такие, как соединения с БД), что используются в веб-приложении.
Это можно сделать настроив соответствующие компоненты в конфигурации консольного
приложения:

~~~
[php]
return array(
	......
	'components'=>array(
		'db'=>array(
			......
		),
	),
);
~~~

Формат конфигурации очень похож на тот, что используется в веб-приложении, так как
и [CConsoleApplication] и [CWebApplication] наследуют один и тот же базовый класс.